﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using KM.Framework.Utility;

namespace KM.Framework.Business
{
    public enum EnumBindingMode
    {
        SourceToTarget = 1,
        TargetToSource = 2,
        TwoWay = 1 | 2,
    }

    public class BindingProperty
    {
        public BindingProperty(string sourcePropertyName, string targetPropertyName, EnumBindingMode bindingMode = EnumBindingMode.TwoWay)
        {
            this.SourcePropertyName = sourcePropertyName;
            this.TargetPropertyName = targetPropertyName;
            this.BindingMode = bindingMode;
        }

        public string SourcePropertyName { get; set; }
        public string TargetPropertyName { get; set; }
        public EnumBindingMode BindingMode { get; set; }

        public bool IsEquals(BindingProperty bindingPerproty)
        {
            return this.SourcePropertyName == bindingPerproty.SourcePropertyName && this.TargetPropertyName == bindingPerproty.TargetPropertyName;
        }
    }

    /// <summary>
    /// 支持不同BindingObj之间进行属性绑定
    /// </summary>
    public class BindingObj : DataEntity
    {
        //用来存放目标BindingObj的绑定属性集合的字典
        private Dictionary<BindingObj, List<BindingProperty>> TargetBindingObjDic = new Dictionary<BindingObj, List<BindingProperty>>();

        public BindingObj()
        {
            this.PropertyChanged += new PropertyChangedEventHandler(BindingObj_PropertyChanged);
        }

        protected bool CompareValue(object val1, object val2)
        {
            if (val1 == val2)
                return true;

            if (val1 != null && val2 != null)
                return val1.Equals(val2);

            return false;
        }

        public void SetBinding(string sourcePropertyName, BindingObj targerObj, string targetPropertyName, EnumBindingMode bindingMode = EnumBindingMode.TwoWay)
        {
            List<BindingProperty> bpList = null;

            if (this.TargetBindingObjDic.ContainsKey(targerObj))
            {
                bpList = this.TargetBindingObjDic[targerObj];
            }
            else
            {
                //只注册一次目标的属性改变时间
                targerObj.PropertyChanged += new PropertyChangedEventHandler(targerObj_PropertyChanged);
                bpList = new List<BindingProperty>();
                this.TargetBindingObjDic.Add(targerObj, bpList);
            }

            BindingProperty bp = new BindingProperty(sourcePropertyName, targetPropertyName, bindingMode);

            foreach (BindingProperty bpTemp in bpList)
            {
                if (bpTemp.IsEquals(bp)) return;//不能重复绑定
            }

            bpList.Add(bp);
        }

        private void CopyPropertyValue(BindingObj targetObj, string targetPropertyName, BindingObj sourceObj, string sourcePropertyName)
        {
            PropertyInfo sp = sourceObj.GetType().GetProperty(sourcePropertyName);
            PropertyInfo tp = targetObj.GetType().GetProperty(targetPropertyName);
            if (sp != null && tp != null)
            {
                object sourceVal = sp.GetValue(sourceObj, null);
                object targetVal = tp.GetValue(targetObj, null);

                if (!CompareValue(sourceVal, targetVal))//判断引用(值)不相等，就为targetObj拷贝sourceVal
                    tp.SetValue(targetObj, sourceVal, null);                
            }
        }

        void targerObj_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (sender is BindingObj)
            {
                BindingObj targetObj = sender as BindingObj;
                if (this.TargetBindingObjDic.ContainsKey(targetObj))
                {
                    List<BindingProperty> bpList = this.TargetBindingObjDic[targetObj];
                    foreach (BindingProperty bp in bpList)
                    {
                        if (e.PropertyName == bp.TargetPropertyName)
                        {
                            if ((bp.BindingMode & EnumBindingMode.TargetToSource) == EnumBindingMode.TargetToSource)
                                this.CopyPropertyValue(this, bp.SourcePropertyName, targetObj, bp.TargetPropertyName);
                        }
                    }
                }
            }
        }

        void BindingObj_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            foreach (BindingObj targetObj in this.TargetBindingObjDic.Keys)
            {
                List<BindingProperty> bpList = this.TargetBindingObjDic[targetObj];
                foreach (BindingProperty bp in bpList)
                {
                    if (e.PropertyName == bp.SourcePropertyName)
                    {
                        if ((bp.BindingMode & EnumBindingMode.SourceToTarget) == EnumBindingMode.SourceToTarget)
                            this.CopyPropertyValue(targetObj, bp.TargetPropertyName, this, bp.SourcePropertyName);
                    }
                }
            }
        }
    }
}
